package com.ccp.dev.workflow.controller;

import com.ccp.dev.core.basic.annotion.Action;
import com.ccp.dev.core.basic.annotion.ActionExecOrder;
import com.ccp.dev.core.basic.consts.UrlConstants;
import com.ccp.dev.core.basic.engine.GroovyScriptEngine;
import com.ccp.dev.core.basic.engine.IScript;
import com.ccp.dev.core.basic.internationalization.SysBaseController;
import com.ccp.dev.core.basic.model.SysAuditModelType;
import com.ccp.dev.core.basic.response.ResultData;
import com.ccp.dev.core.basic.template.IRollBack;
import com.ccp.dev.core.basic.template.RollbackJdbcTemplate;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.basic.web.query.QueryFilter;
import com.ccp.dev.core.util.*;
import com.ccp.dev.core.util.log.SysAuditThreadLocalHolder;
import com.ccp.dev.workflow.model.AliasScript;
import com.ccp.dev.workflow.service.AliasScriptService;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  自定义别名脚本 控制类
 *  2019-11-13
 */

@Controller
@RequestMapping(UrlConstants.PROJECT_ROOT + UrlConstants.PROJECT_MODULE_WORKFLOW + "/aliasScript")
@Action(ownermodel = SysAuditModelType.PROCESS_AUXILIARY)
public class AliasScriptController extends SysBaseController {
    private static final Logger logger = LoggerFactory.getLogger(AliasScriptService.class);

    @Resource
    private RollbackJdbcTemplate rollbackJdbcTemplate;
    @Resource
    private GroovyScriptEngine groovyScriptEngine;
    @Resource
    private AliasScriptService aliasScriptService;

    /**
     * 跳转别名脚本管理页面
     * @return 跳转页面
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + UrlConstants.MODULE_FUNCTION_LIST)
    @Action(description ="别名脚本管理页面跳转",exectype = "页面跳转日志")
    public String listView() {
        return getAutoView();
    }

    /**
     * 获取别名脚本管理页面列表数据
     * @param request
     * @return 返回结果
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_LIST)
    @Action(description = "别名脚本页面列表数据查询",detail = "别名脚本管理页面数据查询成功")
    @ResponseBody
    public ResultData list(HttpServletRequest request) {
        QueryFilter queryFilter = new QueryFilter(request);
        try {
            List<AliasScript> aliasScriptList = aliasScriptService.queryList(queryFilter);
            return getResultDataSuccess("operation.success", queryFilter.getPageBean().getTotalCount(), aliasScriptList);
        } catch (Exception e) {
            logger.error(e.getMessage());
            return getResultDataError("operation.failure");
        }
    }

    /**
     * 跳转新增或编辑页面
     * @param request
     * @param model
     * @return 跳转页面
     * @throws Exception
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/edit")
    @Action(description ="别名脚本管理新增或编辑页面跳转",exectype = "页面跳转日志")
    public String aliasScriptEdit(HttpServletRequest request,Model model) throws Exception {
        String id = RequestUtil.getString(request,"id") ;
        List<Class> implClasses = AppUtil.getImplClass(IScript.class);
        model.addAttribute("implClasses",implClasses);
        if(StringUtil.isNotEmpty(id) ){
            AliasScript aliasScript = aliasScriptService.getOneById(id);
            model.addAttribute("aliasScript",aliasScript);
        }
        return getAutoView();
    }

    /**
     * 跳转明细页面
     * @param request
     * @param model
     * @return
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + UrlConstants.MODULE_FUNCTION_GET)
    @Action(description ="别名脚本管理明细页面跳转",exectype = "页面跳转日志")
    public String aliasScriptGet(HttpServletRequest request,Model model) {
        String id = RequestUtil.getString(request,"id") ;
        AliasScript aliasScript = aliasScriptService.getOneById(id);
        model.addAttribute("aliasScript",aliasScript);
        return getAutoView();
    }


    /**
     * 保存别名脚本
     *
     * @param aliasScript 添加或更新的实体
     * @return
     * @throws Exception
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_SAVE)
    @Action(description = "别名脚本保存或更新",detail = "别名脚本<#if add>保存成功<#elseif update>更新成功<#else>保存失败</#if>")
    @ResponseBody
    public ResultData save(AliasScript aliasScript) {

        try {
            //如果是类型的，以下属性都为空！
            if ("custom".equals(aliasScript.getScriptType())) {
                aliasScript.setClassName("");
                aliasScript.setClassInsName("");
                aliasScript.setMethodName("");
                aliasScript.setMethodDesc("");
                aliasScript.setReturnType("");
                aliasScript.setArgument("");
            } else {
                aliasScript.setScriptComten("");
            }

            if (StringUtil.isEmpty(aliasScript.getId())) {
                aliasScript.setId(UUIDUtils.getUUIDFor32());
                aliasScriptService.addAliasScript(aliasScript);
                SysAuditThreadLocalHolder.putParamerter("add",true);
                return getResultDataSuccess("save.success");
            } else {
                aliasScriptService.update(aliasScript);
                SysAuditThreadLocalHolder.putParamerter("update",true);
                return getResultDataSuccess("update.success");
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            SysAuditThreadLocalHolder.putParamerter("update",true);
            return getResultDataError("save.failure");
        }
    }

    /**
     * 删除别名脚本
     *
     * @param request
     * @return 返回结果
     */
    @RequestMapping(UrlConstants.MODULE_FUNCTION_DELETE)
    @Action(description = "别名脚本删除",execOrder = ActionExecOrder.BEFORE,detail = "<#if success>别名脚本删除成功</#if>")
    @ResponseBody
    public ResultData del(HttpServletRequest request) {
        try {
            String[] lAryId = RequestUtil.getStringAryByStr(request, "ids");
            aliasScriptService.delByIdArray(lAryId);
            SysAuditThreadLocalHolder.putParamerter("success",true);
            return getResultDataSuccess("delete.success");
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            return getResultDataError("delete.failure");
        }
    }
    /**
     * 别名脚本开发帮助
     * @return 返回页面
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/help")
    @Action(description="别名脚本开发帮助",exectype = "页面跳转日志")
    public String goToHelp(){   return getAutoView();   }

    /**
     * 通过类名获取类的所有方法
     * @param request
     * @return 返回结果
     */
    @RequestMapping("/getMethodsByName")
    @Action(description = "通过类名获取类的所有方法",detail = "类名<#assign ent= RequestUtil.getString(request, \"name\")>【${ent}】的所有方法查询成功")
    @ResponseBody
    public ResultData getMethodsByName(@RequestParam String name){
        try{
            JSONArray jarray = aliasScriptService.getMethodsByName(name);
            return getResultDataSuccess("query.success",jarray);
        }
        catch(Exception ex){
            logger.error(ex.getMessage());
            return getResultDataError("query.failure");
        }
    }


    /**
     * 校验自定义别名脚本的名称唯一性
     * @param request
     * @return 返回结果
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @RequestMapping("/checkRepeatName")
    @Action(description="检查别名脚本的别名有没有重复",detail = "别名脚本的别名<#if success>可以使用<#else>已经存在，不可用</#if>")
    @ResponseBody
    public ResultData checkRepeatName(HttpServletRequest request) {
        String id=RequestUtil.getString(request, "id", "");
        String aliasName=RequestUtil.getString(request, "aliasName", "");
        //名称是否为空
        if("".equals(aliasName)){
            return getResultDataError("script.name.null");
        }else{
            boolean isRepeatName = aliasScriptService.checkRepeatName(id,aliasName);
            //名称是否已存在,==true 名称可以使用；==false 名称已存在
            if(isRepeatName){
                //名称不存在，可以使用
                SysAuditThreadLocalHolder.putParamerter("success",true);
                return getResultDataSuccess("script.alias.name.success");
            }else{
                //名称存在，不可以使用
                SysAuditThreadLocalHolder.putParamerter("success",false);
                return getResultDataError("script.alias.name.failure");
            }
        }
    }


    /**
     * 跳转预览页面
     * @param request
     * @return 跳转页面
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX+"/toPreview")
    @Action(description="别名脚本预览页面跳转",exectype = "页面跳转日志")
    public String toPreview(HttpServletRequest request, Model model){
        String scriptStr=RequestUtil.getString(request, "scriptStr");
        scriptStr = StringEscapeUtils.unescapeHtml4(scriptStr);
        String alias=RequestUtil.getString(request, "alias");
        alias = StringEscapeUtils.unescapeHtml4(alias);
        model.addAttribute("scriptStr", scriptStr).addAttribute("alias", alias);
        return getAutoView();
    }

    /**
     * 预览按钮 测试脚本数据内容
     * @param request
     * @return 返回结果
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @RequestMapping("/preview")
    @Action(description="别名脚本内容预览测试",detail = "别名脚本内容预览测试")
    @ResponseBody
    public ResultData preview(HttpServletRequest request){
        final String scriptStr=StringEscapeUtils.unescapeHtml4(RequestUtil.getString(request, "scriptStr", ""));
        String alias=RequestUtil.getString(request, "alias", "");
        alias = StringEscapeUtils.unescapeHtml4(alias);
        Map returnMap=new HashMap();
        if(StringUtil.isEmpty(scriptStr)){
            returnMap.put("isSuccess", 1);
            returnMap.put("msg", "删除");
            returnMap.put("result", "别名脚本内容不能为空！");
            return getResultDataSuccess("script.preview.text.failure",returnMap);
        }else{
            Map map=new HashMap();
            boolean mark = false;
            if(!"".equals(alias)){
                JSONArray array = JSONArray.fromObject(alias);
                for (int i = 0; i < array.size(); i++){
                    JSONObject obj = array.getJSONObject(i);
                    String paraValue = obj.getString("paraValue");
                    String paraType = obj.getString("paraType");
                    if(obj.containsKey("isRequired")&&"1".equals(obj.getString("isRequired"))){
                        if(StringUtil.isEmpty(paraValue)){
                            mark = true;
                            returnMap.put("isSuccess", 2);
                            returnMap.put("msg", obj.getString("paraName")+"别名脚本参数是必填的！");
                            returnMap.put("result", "");
                            break;
                        }
                    }

                    Object javaObj = paraValue;
                    //类型转换
                    if(obj.containsKey("paraType")&&StringUtil.isNotEmpty(paraType)&&StringUtil.isNotEmpty(paraValue)){
                        javaObj = this.getValueObject(paraValue,paraType);
                    }
                    map.put(obj.getString("paraName"),javaObj);
                }
            }
            if(!mark){
                map.put("userId",1);
                //回滚事务的调用方式
                Object result = rollbackJdbcTemplate.executeRollBack(new IRollBack(){
                    @Override
                    public Object execute(String script, Map<String, Object> map){
                        return groovyScriptEngine.executeObject(scriptStr, map);
                    }
                }, scriptStr, map);
                returnMap.put("isSuccess", 0);
                returnMap.put("msg","别名脚本内容测试成功");
                returnMap.put("result", result);
                return getResultDataSuccess("script.preview.success",returnMap);
            }

        }
        return getResultDataSuccess("script.preview.var.failure",returnMap);
    }

    /**
     * 脚本参数的格式转换
     * @param paraValue
     * @param paraType
     * @return 返回数据
     */
    private Object getValueObject(String paraValue,String paraType){
        Object javaObj = paraValue;
        paraType = paraType.toLowerCase();
        if(paraType.contains("string")){
            javaObj = paraValue;
        }else if(paraType.contains("date")){
            javaObj = TimeUtil.convertString(paraValue, "yyyy-MM-dd");
        }else if(paraType.contains("long")){
            javaObj = Long.parseLong(paraValue);
        }else if(paraType.contains("byte")){
            javaObj = paraValue.getBytes();
        }else if(paraType.contains("short")){
            javaObj = Short.parseShort(paraValue);
        }else if(paraType.contains("float")){
            javaObj = Float.parseFloat(paraValue);
        }else if(paraType.contains("char")){
            char[] a = paraValue.toCharArray();
            javaObj = a[0];
        }else if(paraType.contains("double")){
            javaObj = Double.parseDouble(paraValue);
        }else if(paraType.contains("boolean")){
            javaObj = Boolean.parseBoolean(paraValue);
        }else if(paraType.contains("int")){
            javaObj =  Integer.parseInt(paraValue);
        }else if(paraType.contains("map")){
            //暂时不处理
        }else if(paraType.contains("list")){
            //暂时不处理
        }
        return javaObj;
    }

    /**
     * 导出别名脚本xml。
     *
     * @param request
     * @param response
     */
    @RequestMapping("/exportXml")
    @Action(description = "别名脚本导出",detail = "别名脚本导出<#if success>成功<#else>失败</#if>")
    public void exportXml(HttpServletRequest request,HttpServletResponse response){
        String strXml = null;
        String fileName = null;
        String[] tableIds = RequestUtil.getStringAryByStr(request, "tableIds");
        List<AliasScript> list = aliasScriptService.queryList(null);
        try {
            if (BeanUtils.isEmpty(tableIds)) {
                if (BeanUtils.isNotEmpty(list)) {
                    strXml = aliasScriptService.exportXml(list);
                    fileName = "全部别名脚本_"+ DateFormatUtil.getNowByString("yyyyMMddHHmmdd")+ ".xml";
                }

            } else {

                strXml = aliasScriptService.exportXml(tableIds);
                fileName = DateFormatUtil.getNowByString("yyyyMMddHHmmdd")+ ".xml";
                if (tableIds.length == 1) {
                    AliasScript aliasScript = aliasScriptService.getOneById(tableIds[0]);
                    fileName = aliasScript.getAliasName() + "_" + fileName;
                } else if (tableIds.length == list.size()) {
                    fileName = "全部别名脚本_" + fileName;
                } else {
                    fileName = "多条别名脚本_" + fileName;
                }
            }
            FileUtil.downLoad(request, response, strXml, fileName);
            SysAuditThreadLocalHolder.putParamerter("success",true);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            SysAuditThreadLocalHolder.putParamerter("success",false);
        }

    }

    /**
     * 导入页面-弹窗
     *
     * @return 跳转页面
     */
    @RequestMapping(UrlConstants.VIEW_DISPATCH_PREFIX + "/importXml")
    @Action(description = "别名脚本导入页面",exectype = "页面跳转日志")
    public String windowImportXmlList() {
        return getAutoView();
    }

    /**
     * 导入别名脚本的XML
     * @param request
     * @return 返回结果
     */
    @RequestMapping("/importXml")
    @Action(description = "导入别名脚本",detail = "别名脚本导入<#if success>成功<#else>失败</#if>")
    @ResponseBody
    public ResultData importXml(MultipartHttpServletRequest request){
        MultipartFile fileLoad = request.getFile("file");
        try {
            aliasScriptService.importXml(fileLoad.getInputStream());
            SysAuditThreadLocalHolder.putParamerter("success",true);
            return getResultDataSuccess("file.importXml.success");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            SysAuditThreadLocalHolder.putParamerter("success",false);
            //将不能导入的脚本信息存放在result.data属性中
            return getResultDataError("file.importXml.failure",1,e.getMessage());
        }
    }
}
